package com.iwomy.secureplat.platform.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.iwomy.secureplat.common.core.util.R;
import com.iwomy.secureplat.platform.dto.SensorTransmissionDataDto;
import com.iwomy.secureplat.platform.entity.BasicDeviceEntity;
import com.iwomy.secureplat.platform.service.BasicDeviceService;
import com.iwomy.secureplat.platform.service.HistoricalDataService;
import com.iwomy.secureplat.platform.transmission.entity.SensorTransmissionData;
import com.iwomy.secureplat.platform.transmission.entity.SensorTransmissionDataDetails;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 历史数据表
 *
 * @author pig
 * @date 2024-01-29 09:58:08
 */
@Service
public class HistoricalDataServiceImpl implements HistoricalDataService {

	@Resource
	private MongoTemplate mongoTemplate;

	@Resource
	private BasicDeviceService deviceService;

	@Override
	public JSONObject historicalData(SensorTransmissionDataDto sensorTransmissionDataDto) throws Exception {
		List<SensorTransmissionData> list = this.getSensorTransmissionDataList(sensorTransmissionDataDto);
		if (ObjectUtil.isEmpty(list)) return null;

		List<LocalDateTime> x = new LinkedList();
		Map<String, List<Double>> yMap = new HashMap<>();

		for (SensorTransmissionData transmissionData : list) {
			List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = transmissionData.getSensorTransmissionDataDetailsList();
			x.add(transmissionData.getReceptionTime());
			if (ObjectUtil.isEmpty(sensorTransmissionDataDetailsList)) {
				continue;
			}
			for (SensorTransmissionDataDetails details : sensorTransmissionDataDetailsList) {
				String sensorValStr = details.getSensorVal();

				// 将 sensorValStr 转换为 double 类型
				try {
					double sensorVal = Double.parseDouble(sensorValStr);
					// 添加到对应的 yMap 中
					List<Double> yList = yMap.getOrDefault(details.getSensorTypeName(), new ArrayList<>());
					yList.add(sensorVal);
					yMap.put(details.getSensorTypeName(), yList);
				} catch (NumberFormatException e) {
					// 处理转换异常
					System.out.println("传感器值转换异常：" + sensorValStr);
				}
			}
		}

		JSONObject jsonObject = new JSONObject();
		jsonObject.put("x", x);
		for (String gasTypeIdAndUnit : yMap.keySet()) {
			List<Double> yList = new ArrayList<>(); // 为每个键创建一个对应的 y 值列表
			for (SensorTransmissionData transmissionData : list) {
				List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = transmissionData.getSensorTransmissionDataDetailsList();
				if (ObjectUtil.isEmpty(sensorTransmissionDataDetailsList)) {
					yList.add(0.0); // 如果详情列表为空，添加 0 到 y 列表
					continue;
				}
				List<SensorTransmissionDataDetails> collect = sensorTransmissionDataDetailsList.stream()
						.filter(i -> gasTypeIdAndUnit.equals(i.getSensorTypeName())).collect(Collectors.toList());
				if (ObjectUtil.isEmpty(collect)) {
					yList.add(0.0); // 如果未找到匹配的 gasTypeIdAndUnit，添加 0 到 y 列表
					continue;
				}
				SensorTransmissionDataDetails sensorTransmissionDataDetails = collect.get(0);
				yList.add(Double.parseDouble(sensorTransmissionDataDetails.getSensorVal()));
			}
			jsonObject.put(gasTypeIdAndUnit, yList); // 将每个键对应的 y 值列表添加到 JSON 对象中
		}

		return jsonObject;
	}

	private List<SensorTransmissionData> getSensorTransmissionDataList(SensorTransmissionDataDto sensorTransmissionDataDto) {
		Criteria criteria = Criteria.where("deviceUniqueId").is(sensorTransmissionDataDto.getImei());

		LocalDateTime[] createTime = sensorTransmissionDataDto.getCreateTime();
		if (ObjectUtil.isNotEmpty(createTime)) {
			criteria.andOperator(
					Criteria.where("receptionTime").gte(createTime[0]),
					Criteria.where("receptionTime").lte(createTime[1])
			);
		}
		if (ObjectUtil.isNotEmpty(sensorTransmissionDataDto.getAlarmEventTypeCode())) {
			criteria.and("alarmInfo").is(sensorTransmissionDataDto.getAlarmEventTypeCode());
		}
		if (ObjectUtil.isNotEmpty(sensorTransmissionDataDto.getAlarmEventTypeName())) {
			criteria.and("alarmEvenName").is(sensorTransmissionDataDto.getAlarmEventTypeName());
		}

		Query query = new Query(criteria);
		if (ObjectUtil.isNotEmpty(sensorTransmissionDataDto.getDeviceOverview())){
			query.with(Sort.by(Sort.Direction.ASC, "receptionTime"));
		}else {
			query.with(Sort.by(Sort.Direction.DESC, "receptionTime"));
		}
		
		List<SensorTransmissionData> result = mongoTemplate.find(query, SensorTransmissionData.class);
		if (ObjectUtil.isEmpty(result)) return null;

		// 生成包含所有时间点的列表
		List<LocalDateTime> timePoints = new ArrayList<>();
		LocalDateTime currentTime = createTime[0];
		// 匹配查询结果中的数据与时间点列表，并将结果加入新的列表中
		List<SensorTransmissionData> resultList = new ArrayList<>();

		if (sensorTransmissionDataDto.getRange().equals("RealTime")) {
			return result;

		} else if (sensorTransmissionDataDto.getRange().equals("HourlyAvg")) {
			while (currentTime.isBefore(createTime[1])) {
				timePoints.add(currentTime);
				currentTime = currentTime.plusHours(1);
			}
			this.hourlyAvg(timePoints, result, resultList);
		} else if (sensorTransmissionDataDto.getRange().equals("DailyAvg")) {
			while (currentTime.isBefore(createTime[1])) {
				timePoints.add(currentTime);
				currentTime = currentTime.plusDays(1);
			}
			this.dailyAvg(timePoints, result, resultList);
		}
		return resultList;
	}

	@Override
	public List<SensorTransmissionData> hourlyAvg(List<LocalDateTime> timePoints, List<SensorTransmissionData> result, List<SensorTransmissionData> resultList) {
		for (LocalDateTime time : timePoints) {
			boolean isDataFound = false;
			SensorTransmissionData closestData = null;
			Duration closestDuration = null;

			for (SensorTransmissionData data : result) {
				LocalDateTime receptionTime = data.getReceptionTime().truncatedTo(ChronoUnit.SECONDS);

				if (receptionTime.isBefore(time)) {
					continue;  // 如果数据的接收时间在指定时间点之后，则跳过该条数据
				}

				Duration duration = Duration.between(receptionTime, time.truncatedTo(ChronoUnit.SECONDS));

				if (duration.isNegative()) {
					duration = duration.negated();
				}

				if (duration.compareTo(Duration.ofMinutes(60)) <= 0 && (closestDuration == null || duration.compareTo(closestDuration) < 0)) {
					closestData = data;
					closestDuration = duration;
				}
			}

			if (closestData != null) {
				resultList.add(closestData);
				isDataFound = true;
			} else {
				// 如果数据库中没有对应的数据，则创建一个空的SensorTransmissionData对象并添加到结果列表中
				SensorTransmissionData emptyData = new SensorTransmissionData();
				emptyData.setReceptionTime(time);
				resultList.add(emptyData);
			}
		}
		return resultList;
	}

	@Override
	public List<SensorTransmissionData> dailyAvg(List<LocalDateTime> timePoints, List<SensorTransmissionData> result, List<SensorTransmissionData> resultList) {
		for (LocalDateTime time : timePoints) {
			boolean isDataFound = false;
			SensorTransmissionData closestData = null;
			Duration closestDuration = null;

			for (SensorTransmissionData data : result) {
				LocalDateTime receptionTime = data.getReceptionTime().truncatedTo(ChronoUnit.SECONDS);

				if (receptionTime.isBefore(time)) {
					continue;  // 如果数据的接收时间在指定时间点之后，则跳过该条数据
				}

				Duration duration = Duration.between(receptionTime, time.truncatedTo(ChronoUnit.SECONDS));

				if (duration.isNegative()) {
					duration = duration.negated();
				}

				if (duration.compareTo(Duration.ofHours(24)) <= 0 && (closestDuration == null || duration.compareTo(closestDuration) < 0)) {
					closestData = data;
					closestDuration = duration;
				}
			}

			if (closestData != null) {
				resultList.add(closestData);
				isDataFound = true;
			} else {
				// 如果数据库中没有对应的数据，则创建一个空的SensorTransmissionData对象并添加到结果列表中
				SensorTransmissionData emptyData = new SensorTransmissionData();
				emptyData.setReceptionTime(time);
				resultList.add(emptyData);
			}
		}
		return resultList;
	}

	@Override
	public R deviceOverview(SensorTransmissionDataDto sensorTransmissionDataDto){
		LocalDateTime nowTime = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
		LocalDateTime minutesAgo = nowTime.minusMinutes(15).truncatedTo(ChronoUnit.SECONDS);

		LocalDateTime[] createTime = new LocalDateTime[2];
		createTime[0] = minutesAgo;
		createTime[1] = nowTime;

		sensorTransmissionDataDto.setCreateTime(createTime);
		sensorTransmissionDataDto.setRange("RealTime");
		sensorTransmissionDataDto.setDeviceOverview("设备总览");

		try {
			return R.ok(historicalData(sensorTransmissionDataDto));
		} catch (Exception e) {
			System.out.println("e.getMessage()==============="+e.getMessage());
			return R.failed(e.getMessage());
		}
	}

	@Override
	public List export(SensorTransmissionDataDto sensorTransmissionDataDto) {
		Criteria criteria = Criteria
				.where("deviceUniqueId").is(sensorTransmissionDataDto.getImei());

		LocalDateTime[] createTime = sensorTransmissionDataDto.getCreateTime();

		if (ObjectUtil.isNotEmpty(createTime)) {
			criteria.andOperator(
					Criteria.where("receptionTime").gte(createTime[0]),
					Criteria.where("receptionTime").lte(createTime[1])
			);
		}

		Query query = new Query(criteria);
		query.with(Sort.by(Sort.Direction.DESC, "receptionTime"));

		List<SensorTransmissionData> result = mongoTemplate.find(query, SensorTransmissionData.class);

		BasicDeviceEntity deviceEntity = deviceService.getHistoricalImei(sensorTransmissionDataDto.getImei());
		// 生成包含所有时间点的列表
		List<LocalDateTime> timePoints = new ArrayList<>();
		LocalDateTime currentTime = createTime[0];

		// 匹配查询结果中的数据与时间点列表，并将结果加入新的列表中
		List<SensorTransmissionData> resultList = new ArrayList<>();

		if (sensorTransmissionDataDto.getRange().equals("RealTime")) {
			for (SensorTransmissionData transmissionData : result) {
				transmissionData.setDeviceType(deviceEntity.getDeviceTypeName());
				transmissionData.setDeviceModelName(deviceEntity.getDeviceModelName());
				transmissionData.setImei(deviceEntity.getImei());
			}
			return result;
		} else if (sensorTransmissionDataDto.getRange().equals("HourlyAvg")) {
			while (currentTime.isBefore(createTime[1])) {
				timePoints.add(currentTime);
				currentTime = currentTime.plusHours(1);
			}
			resultList = hourlyAvg(timePoints, result, resultList);
		} else if (sensorTransmissionDataDto.getRange().equals("DailyAvg")) {
			while (currentTime.isBefore(createTime[1])) {
				timePoints.add(currentTime);
				currentTime = currentTime.plusDays(1);
			}
			resultList =dailyAvg(timePoints, result, resultList);
		}
		for (SensorTransmissionData transmissionData : resultList) {
			transmissionData.setDeviceType(deviceEntity.getDeviceTypeName());
			transmissionData.setDeviceModelName(deviceEntity.getDeviceModelName());
			transmissionData.setImei(deviceEntity.getImei());
		}
		return resultList;
	}
}